package src;
import src.Base.ErrorLog;
import src.Base.Word;

import javax.swing.*;
import java.io.*;
import java.util.*;

import static java.lang.reflect.Array.getChar;
public class Lexer {
    static void log(String msg){
        System.out.println(msg);
    }
    static boolean isLetterOrUnderline(char c){
        return Character.isLetter(c) || c == '_';
    }
    static boolean isDigit(char c){
        return Character.isDigit(c);
    }
    int strLen; //读入的行的长度
    int index; //读指针
    int flag = 0;//注释模式标识， 0-无注释，1多行注释
    char[] charArray; //读入行的字符数组
    private static final Map<String, String> TOKENS = new LinkedHashMap<>();
    private static final Map<String, String> RESERVED_WORD= new LinkedHashMap<>();

    ArrayList<Word> wordArrayList = new ArrayList<>();// 识别出的单词
    ArrayList<Word> AllWords = new ArrayList<>();
    private void init(){
        initTOKENS();
    }
    private void initTOKENS(){
        // 关键字和保留字
        RESERVED_WORD.put("intConst", "INTCON");
        RESERVED_WORD.put("main", "MAINTK");
        RESERVED_WORD.put("for", "FORTK");
        RESERVED_WORD.put("const", "CONSTTK");
        RESERVED_WORD.put("getint", "GETINTTK");
        RESERVED_WORD.put("int", "INTTK");
        RESERVED_WORD.put("printf", "PRINTFTK");
        RESERVED_WORD.put("break", "BREAKTK");
        RESERVED_WORD.put("return", "RETURNTK");
        RESERVED_WORD.put("continue", "CONTINUETK");
        RESERVED_WORD.put("if", "IFTK");
        RESERVED_WORD.put("else", "ELSETK");
        RESERVED_WORD.put("void", "VOIDTK");

        //组合符号
        TOKENS.put("&&", "AND");
        TOKENS.put("||", "OR");
        TOKENS.put("<=", "LEQ");
        TOKENS.put(">=", "GEQ");
        TOKENS.put("==", "EQL");
        TOKENS.put("!=", "NEQ");
        //简单符号
        TOKENS.put(">", "GRE");
        TOKENS.put("!", "NOT");
        TOKENS.put("*", "MULT");
        TOKENS.put("=", "ASSIGN");
        TOKENS.put("/", "DIV");
        TOKENS.put(";", "SEMICN");
        TOKENS.put("%", "MOD");
        TOKENS.put(",", "COMMA");
        TOKENS.put("<", "LSS");
        TOKENS.put("(", "LPARENT");
        TOKENS.put(")", "RPARENT");
        TOKENS.put("[", "LBRACK");
        TOKENS.put("]", "RBRACK");
        TOKENS.put("{", "LBRACE");
        TOKENS.put("}", "RBRACE");
        TOKENS.put("+", "PLUS");
        TOKENS.put("-", "MINU");


    }
    public Lexer(){
        init();
    }

    public ArrayList<Word> getWordArrayList() {
        return AllWords;
    }

    public void getOneWord(String str, int line){
        index = 0;
        strLen = str.length();
        charArray = str.toCharArray();
        wordArrayList.clear();
        char c;
        //System.out.println("line:"+ line);
        while(true){
            int temp = getchar();
            if(temp == -1){
                break;
            }
            if(flag == 1){ //多行注释情况
                while (index < strLen){
                    if(temp == 42){ // (char)42 -- "*"
                        temp = getchar();
                        if(temp == 47){ // (char)47 -- "/"
                            flag = 0;
                            //System.out.println(str+"end of the 注释");
                            break;
                        }else {
                            index--;
                        }
                    }
                    temp = getchar();
                }
                continue;
            }
            c = (char)temp;
            //System.out.println("now char = " + c);
            if(c == ' '||c == '\r'||c =='\n'||c == '\t'){
                continue;
            }else if (c == '/'){
                annotationHandle(line);
            }else if(isDigit(c)){
                int num = c - '0';
                int tmp;
                while ((tmp = getchar()) != -1){
                    if(!isDigit((char)tmp)){
                        index--;
                        break;
                    }
                    tmp = tmp - 48; // '0' - ascii:48
                    num = num*10 + tmp;
                }
                addNewWord(line, "INTCON",String.valueOf(num));
            }else if(isLetterOrUnderline(c)){
                StringBuilder stringBuilder = new StringBuilder(String.valueOf(c));
                while((temp = getchar()) != -1){
                    if(!isLetterOrUnderline((char)temp) && !isDigit((char)temp)){
                        index--;
                        break;
                    }
                    stringBuilder.append((char) temp);
                }
                String ident = stringBuilder.toString();
                String type = RESERVED_WORD.getOrDefault(ident, "IDENFR");
                addNewWord(line, type, ident);
            }else if(c == '"'){
                StringBuilder stringBuilder = new StringBuilder("\"");
                boolean flag92 = false; //前一个字符为'\'
                boolean flag37 = false; //前一个字符为'%'
                while((temp = getchar()) != -1){
                    if(isLegalChar(temp)){
                        //ASCII: 110 - 'n' 100 - 'd'
                        if(flag92 && temp != 110){
                            // \n %d
                            ErrorLog.instance.addError(line, "a");
                        }else{
                            flag92 = false;
                        }
                        if(flag37 && temp != 100){
                            ErrorLog.instance.addError(line, "a");
                        }else {
                            flag37 = false;
                        }
                        if(temp == 92){
                            flag92 = true;
                        }
                        if(temp == 37){
                            flag37 = true;
                        }
                        stringBuilder.append((char) temp);
                    }else if(temp == 34){
                        if (flag92 || flag37){
                            if(!ErrorLog.instance.repeatErrorA(line)){
                                ErrorLog.instance.addError(line, "a");
                            }
                        }
                        break;
                    }else{
                        System.out.println((char)temp);
                        ErrorLog.instance.addError(line, "a");
                    }
                }
                String FormatString = stringBuilder.toString();
                addNewWord(line, "STRCON", FormatString);
            }else {
                remainingTokens(str, line);//处理非注释，数字，字符串，标识符情况
            }
            //System.out.println((char) temp);
        }
        //printWordList();
    }


    private boolean isLegalChar(int temp) {
        //为32,33,40-126, 37(%)
        return temp == 32 || temp == 33 || (temp >= 40 && temp <=126) || temp == 37;
    }

    private int getchar(){
        if(index >= strLen){
            return -1;
        }
        char c = getChar(charArray, index);
        index++;
        return c;
    }

    private void annotationHandle(int line){
        int temp = getchar();
        char ch;
        if(temp==-1){//行末尾的 / 当做除号处理
            String type = TOKENS.get("/");
            addNewWord(line, type, "/");
        }else{
            ch = (char)temp;
            String s = String.valueOf(ch);
            if(s.equals("/")){// 双//注释,行后全清除
               index = strLen;
            }else if(s.equals("*")){
                flag = 1;
            }else {// 不是注释情况，当前字符为/，其后字符仍需识别，index--
                index--;
                addNewWord(line, "DIV", "/");
            }
        }
    }

    /***
     * 处理非数字 字符串 标识符
     * @param s 读入行
     * @param line 行号
     */
    private void remainingTokens(String s, int line){
        int flag = 0;
        //System.out.println("log:");
        //System.out.print("index = "+index + " " +charArray[index - 1] + " " + charArray[index] + "\n");
        index--;
        String msg = "this is base msg";
        for(String token:TOKENS.keySet()){
            if(s.substring(index).startsWith(token)){
                //System.out.println(s.substring(index)+" tokens:"+token);
                String type = TOKENS.get(token);
                addNewWord(line, type, token);
                index += token.length();
                flag = 1;
                //msg = token;
                break;
            }
        }
        if(flag != 1){
        System.out.println((char)index + " not match!!");
        }else{
            //log(msg);
        }
    }

    /***
     *
     * @param line 行号
     * @param type 符号类别码
     * @param content 符号内容
     */
    private void addNewWord(int line, String type, String content){
        Word temp = new Word(line, type, content);
        wordArrayList.add(temp);
        AllWords.add(temp);
    }
    private void error(int line){
        String msg = "error at line:"+String.valueOf(line);
        System.out.println(msg);
    }
    private void printWordList() {
        String outPut;
        for (Word word : wordArrayList) {
            outPut = "";
            outPut += word.getType();
            outPut += " ";
            outPut += word.getContent();
            Writer.instance.write("out.txt", outPut + "\n");
            System.out.println(outPut);
        }
    }

}
/* **** *  /// / *  /*** */
